use anyhow::Result;
use base64::{Engine as _, engine::general_purpose};
use chrono::{DateTime, Utc};
use futures::{SinkExt, StreamExt};
use hmac::{Hmac, Mac};
use serde::{Deserialize, Serialize};
use serde_json::json;
use sha2::{Sha256, Digest};
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};
use url::Url;
use futures::stream::{self, BoxStream};

const STATUS_FIRST_FRAME: i32 = 0;  // 第一帧的标识
const STATUS_CONTINUE_FRAME: i32 = 1;  // 中间帧标识
const STATUS_LAST_FRAME: i32 = 2;  // 最后一帧的标识

#[derive(Debug, Serialize, Deserialize)]
struct CommonArgs {
    app_id: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct BusinessArgs {
    aue: String,
    auf: String,
    vcn: String,
    tte: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct DataArgs {
    status: i32,
    text: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct TtsRequest {
    common: CommonArgs,
    business: BusinessArgs,
    data: DataArgs,
}

#[derive(Debug, Serialize, Deserialize)]
struct TtsResponse {
    code: i32,
    sid: Option<String>,
    message: Option<String>,
    data: Option<TtsData>,
}

#[derive(Debug, Serialize, Deserialize)]
struct TtsData {
    audio: Option<String>,
    status: i32,
}

#[derive(Clone)]
pub struct SpeechSynthesizer {
    app_id: String,
    api_key: String,
    api_secret: String,
}

impl SpeechSynthesizer {
    pub fn new(app_id: String, api_key: String, api_secret: String) -> Self {
        Self {
            app_id,
            api_key,
            api_secret,
        }
    }

    fn create_url(&self, text: &str) -> Result<String> {
        let url = "wss://tts-api.xfyun.cn/v2/tts";
        
        // 生成RFC1123格式的时间戳
        let now: DateTime<Utc> = Utc::now();
        let date = now.format("%a, %d %b %Y %H:%M:%S GMT").to_string();

        // 拼接字符串
        let signature_origin = format!(
            "host: {}\ndate: {}\nGET {} HTTP/1.1",
            "ws-api.xfyun.cn",
            date,
            "/v2/tts"
        );

        // 进行hmac-sha256进行加密
        let mut mac = Hmac::<Sha256>::new_from_slice(self.api_secret.as_bytes())?;
        mac.update(signature_origin.as_bytes());
        let signature_sha = general_purpose::STANDARD.encode(mac.finalize().into_bytes());

        let authorization_origin = format!(
            "api_key=\"{}\", algorithm=\"{}\", headers=\"{}\", signature=\"{}\"",
            self.api_key,
            "hmac-sha256",
            "host date request-line",
            signature_sha
        );
        let authorization = general_purpose::STANDARD.encode(authorization_origin.as_bytes());

        // 构建URL参数
        let mut url_with_params = Url::parse(url)?;
        url_with_params.query_pairs_mut()
            .append_pair("authorization", &authorization)
            .append_pair("date", &date)
            .append_pair("host", "ws-api.xfyun.cn");

        Ok(url_with_params.to_string())
    }

    pub async fn synthesize_to_file(&self, text: &str, output_path: &str) -> Result<()> {
        let url = self.create_url(text)?;
        println!("WebSocket URL: {}", url);

        // 删除已存在的文件
        if Path::new(output_path).exists() {
            std::fs::remove_file(output_path)?;
        }

        // 连接WebSocket
        let (ws_stream, _) = connect_async(url).await?;
        println!("WebSocket连接已建立");

        let (mut write, mut read) = ws_stream.split();

        // 准备请求数据
        let request = TtsRequest {
            common: CommonArgs {
                app_id: self.app_id.clone(),
            },
            business: BusinessArgs {
                aue: "raw".to_string(),
                auf: "audio/L16;rate=16000".to_string(),
                vcn: "x4_yezi".to_string(),
                tte: "utf8".to_string(),
            },
            data: DataArgs {
                status: STATUS_LAST_FRAME,
                text: general_purpose::STANDARD.encode(text.as_bytes()),
            },
        };

        let request_json = serde_json::to_string(&request)?;
        println!("------>开始发送文本数据");
        
        // 发送请求
        write.send(Message::Text(request_json)).await?;

        // 打开输出文件
        let mut output_file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(output_path)?;

        // 接收响应
        while let Some(msg) = read.next().await {
            match msg? {
                Message::Text(text) => {
                    println!("收到原始响应: {}", text);
                    let response: TtsResponse = serde_json::from_str(&text)?;
                    println!("解析后响应: {:?}", response);

                    if let Some(data) = response.data {
                        if response.code != 0 {
                            if let Some(err_msg) = response.message {
                                let sid = response.sid.as_deref().unwrap_or("unknown");
                                println!("sid:{} call error:{} code is:{}", 
                                    sid, err_msg, response.code);
                            }
                        } else {
                            // 解码音频数据并写入文件
                            if let Some(audio_str) = data.audio {
                                let audio_data = general_purpose::STANDARD.decode(audio_str)?;
                                output_file.write_all(&audio_data)?;
                            }
                            
                            if data.status == STATUS_LAST_FRAME {
                                println!("WebSocket连接已关闭");
                                break;
                            }
                        }
                    }
                }
                Message::Close(_) => {
                    println!("WebSocket连接已关闭");
                    break;
                }
                _ => {}
            }
        }

        println!("语音合成完成，输出文件: {}", output_path);
        Ok(())
    }

    pub async fn synthesize_to_bytes(&self, text: &str) -> Result<Vec<u8>> {
        let url = self.create_url(text)?;
        println!("WebSocket URL: {}", url);

        // 连接WebSocket
        let (ws_stream, _) = connect_async(url).await?;
        println!("WebSocket连接已建立");

        let (mut write, mut read) = ws_stream.split();

        // 准备请求数据
        let request = TtsRequest {
            common: CommonArgs {
                app_id: self.app_id.clone(),
            },
            business: BusinessArgs {
                aue: "raw".to_string(),
                auf: "audio/L16;rate=16000".to_string(),
                vcn: "x4_yezi".to_string(),
                tte: "utf8".to_string(),
            },
            data: DataArgs {
                status: STATUS_LAST_FRAME,
                text: general_purpose::STANDARD.encode(text.as_bytes()),
            },
        };

        let request_json = serde_json::to_string(&request)?;
        println!("------>开始发送文本数据");
        
        // 发送请求
        write.send(Message::Text(request_json)).await?;

        let mut audio_data = Vec::new();

        // 接收响应
        while let Some(msg) = read.next().await {
            match msg? {
                Message::Text(text) => {
                    println!("收到原始响应: {}", text);
                    let response: TtsResponse = serde_json::from_str(&text)?;
                    println!("解析后响应: {:?}", response);

                    if let Some(data) = response.data {
                        if response.code != 0 {
                            if let Some(err_msg) = response.message {
                                let sid = response.sid.as_deref().unwrap_or("unknown");
                                println!("sid:{} call error:{} code is:{}", 
                                    sid, err_msg, response.code);
                            }
                        } else {
                            // 解码音频数据并添加到结果中
                            if let Some(audio_str) = data.audio {
                                let decoded_audio = general_purpose::STANDARD.decode(audio_str)?;
                                audio_data.extend(decoded_audio);
                            }
                            
                            if data.status == STATUS_LAST_FRAME {
                                println!("WebSocket连接已关闭");
                                break;
                            }
                        }
                    }
                }
                Message::Close(_) => {
                    println!("WebSocket连接已关闭");
                    break;
                }
                _ => {}
            }
        }

        println!("语音合成完成，音频数据大小: {} 字节", audio_data.len());
        Ok(audio_data)
    }

    /// 将PCM数据封装为WAV格式
    fn pcm_to_wav(pcm_data: &[u8], sample_rate: u32, bits_per_sample: u16, channels: u16) -> Vec<u8> {
        let mut wav_data = Vec::new();
        let data_len = pcm_data.len() as u32;
        let header_len = 44u32;
        let byte_rate = sample_rate * channels as u32 * (bits_per_sample as u32) / 8;
        let block_align = channels * bits_per_sample / 8;

        // RIFF header
        wav_data.extend(b"RIFF");
        wav_data.extend(&(data_len + header_len - 8).to_le_bytes());
        wav_data.extend(b"WAVE");

        // fmt chunk
        wav_data.extend(b"fmt ");
        wav_data.extend(&(16u32).to_le_bytes()); // Subchunk1Size
        wav_data.extend(&(1u16).to_le_bytes()); // AudioFormat = PCM
        wav_data.extend(&(channels).to_le_bytes());
        wav_data.extend(&(sample_rate).to_le_bytes());
        wav_data.extend(&(byte_rate).to_le_bytes());
        wav_data.extend(&(block_align).to_le_bytes());
        wav_data.extend(&(bits_per_sample).to_le_bytes());

        // data chunk
        wav_data.extend(b"data");
        wav_data.extend(&(data_len).to_le_bytes());
        wav_data.extend(pcm_data);

        wav_data
    }

    pub async fn synthesize_to_wav_bytes(&self, text: &str) -> Result<Vec<u8>> {
        let pcm_data = self.synthesize_to_bytes(text).await?;
        // 讯飞接口参数: 16k采样率，16位，1声道
        let wav_data = Self::pcm_to_wav(&pcm_data, 16000, 16, 1);
        Ok(wav_data)
    }

    pub async fn stream_pcm_frames(&self, text: &str) -> anyhow::Result<BoxStream<'static, anyhow::Result<Vec<u8>>>> {
        let url = self.create_url(text)?;
        let (ws_stream, _) = connect_async(url).await?;
        let (mut write, mut read) = ws_stream.split();

        // 构造请求
        let request = TtsRequest {
            common: CommonArgs {
                app_id: self.app_id.clone(),
            },
            business: BusinessArgs {
                aue: "raw".to_string(),
                auf: "audio/L16;rate=16000".to_string(),
                vcn: "x4_yezi".to_string(),
                tte: "utf8".to_string(),
            },
            data: DataArgs {
                status: STATUS_LAST_FRAME,
                text: general_purpose::STANDARD.encode(text.as_bytes()),
            },
        };
        let request_json = serde_json::to_string(&request)?;
        write.send(Message::Text(request_json)).await?;

        // 返回异步流
        let stream = stream::unfold(read, |mut read| async {
            match read.next().await {
                Some(Ok(Message::Text(text))) => {
                    println!("Stream收到原始响应: {}", text);
                    let response: TtsResponse = match serde_json::from_str(&text) {
                        Ok(r) => r,
                        Err(e) => return Some((Err(anyhow::anyhow!(e)), read)),
                    };
                    println!("Stream解析后响应: {:?}", response);
                    if let Some(data) = response.data {
                        if response.code != 0 {
                            let err = response.message.unwrap_or_else(|| "TTS错误".to_string());
                            return Some((Err(anyhow::anyhow!(err)), read));
                        } else {
                            if let Some(audio_str) = data.audio {
                                let audio_data = match general_purpose::STANDARD.decode(audio_str) {
                                    Ok(d) => d,
                                    Err(e) => return Some((Err(anyhow::anyhow!(e)), read)),
                                };
                                return Some((Ok(audio_data), read));
                            }
                        }
                    }
                    None
                }
                Some(Ok(Message::Close(_))) | None => None,
                Some(Err(e)) => Some((Err(anyhow::anyhow!(e)), read)),
                _ => None,
            }
        });
        Ok(Box::pin(stream))
    }
}
